﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;
using System.Text.RegularExpressions;
using System.Web.Mvc;

namespace VietThinks.Web
{
    public class LowercaseRoute : Route
    {
        public LowercaseRoute(string url, IRouteHandler routeHandler)
            : base(url, routeHandler) { }
        public LowercaseRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
            : base(url, defaults, routeHandler) { }
        public LowercaseRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler)
            : base(url, defaults, constraints, routeHandler) { }
        public LowercaseRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler)
            : base(url, defaults, constraints, dataTokens, routeHandler) { }

        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            VirtualPathData path = base.GetVirtualPath(requestContext, values);

            if (path != null)
                path.VirtualPath = path.VirtualPath;//.ToLowerInvariant();

            return path;
        }
    }

    public class RegexRoute : Route
    {
        #region Private Fields

        private readonly Regex urlRegex;

        #endregion

        #region Constructors

        public RegexRoute(Regex urlPattern, IRouteHandler routeHandler)
            : this(urlPattern, null, routeHandler)
        {

        }

        public RegexRoute(Regex urlPattern, RouteValueDictionary defaults, IRouteHandler routeHandler)
            : base(null, defaults, routeHandler)
        {
            urlRegex = urlPattern;
        }

        #endregion

        #region Public Overrides Methods

        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            var requestUrl = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;

            var match = urlRegex.Match(requestUrl);

            RouteData data = null;

            if (match.Success)
            {
                data = new RouteData(this, RouteHandler);

                // add defaults first
                if (null != Defaults)
                {
                    foreach (var def in Defaults)
                    {
                        data.Values[def.Key] = def.Value;
                    }
                }

                // iterate matching groups
                for (var i = 1; i < match.Groups.Count; i++)
                {
                    var group = match.Groups[i];

                    if (!group.Success) continue;
                    var key = urlRegex.GroupNameFromNumber(i);

                    if (!String.IsNullOrEmpty(key) && !Char.IsNumber(key, 0))
                    {
                        data.Values[key] = group.Value;
                    }
                }
            }

            return data;
        }

        #endregion
    }

    public static class RouteCollectionExtensions
    {
        public static Route MapRouteEx(this RouteCollection routes, string name, string url)
        {
            return MapRouteEx(routes, name, url, null, null, null, null);
        }

        public static Route MapRouteEx(this RouteCollection routes, string name, string url, object defaults)
        {
            return MapRouteEx(routes, name, url, defaults, null, null, null);
        }

        public static Route MapRouteEx(this RouteCollection routes, string name, Regex urlPattern, object defaults)
        {
            return MapRouteEx(routes, name, null, defaults, null, null, urlPattern);
        }

        public static Route MapRouteEx(this RouteCollection routes, string name, string url, string[] namespaces)
        {
            return MapRouteEx(routes, name, url, null, null, namespaces, null);
        }

        public static Route MapRouteEx(this RouteCollection routes, string name, string url, object defaults, object constraints)
        {
            return MapRouteEx(routes, name, url, defaults, constraints, null, null);
        }

        public static Route MapRouteEx(this RouteCollection routes, string name, string url, object defaults, string[] namespaces)
        {
            return MapRouteEx(routes, name, url, defaults, null, namespaces, null);
        }

        public static Route MapRouteEx(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces, Regex urlPattern)
        {
            if (routes == null)
            {
                throw new ArgumentNullException("routes");
            }
            if (url == null && urlPattern == null)
            {
                throw new ArgumentNullException("url");
            }

            Route route;

            if (urlPattern != null)
            {
                route = new RegexRoute(urlPattern, new MvcRouteHandler())
                {
                    Defaults = new RouteValueDictionary(defaults),
                    Constraints = new RouteValueDictionary(constraints)
                };
            }
            else
            {
                route = new LowercaseRoute(url, new MvcRouteHandler())
                {
                    Defaults = new RouteValueDictionary(defaults),
                    Constraints = new RouteValueDictionary(constraints)
                };
            }

            if (namespaces != null && namespaces.Length > 0)
            {
                route.DataTokens = new RouteValueDictionary();
                route.DataTokens["Namespaces"] = namespaces;
            }

            routes.Add(name, route);

            return route;
        }
    }
}